package org.microframework.cloud.gateway.config;

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 访问控制配置加载器
 * 从Nacos加载黑白名单配置，并定期刷新
 */
@Slf4j
@Component
@RefreshScope
@ConditionalOnProperty(prefix = "spring.cloud.gateway.security.access-control", name = "enabled", havingValue = "true", matchIfMissing = true)
public class AccessControlConfigLoader {

    @Autowired
    private AccessControlProperties accessControlProperties;

    @Autowired
    private NacosConfigManager nacosConfigManager;

    @Autowired
    private ObjectMapper objectMapper;

    @Value("${spring.cloud.nacos.config.group:DEFAULT_GROUP}")
    private String group;

    private ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);

    @PostConstruct
    public void init() {
        if (!accessControlProperties.isEnabled()) {
            log.info("访问控制功能未启用");
            return;
        }

        try {
            // 初始加载配置
            loadConfig();

            // 添加Nacos配置监听器
            addConfigListener();

            // 定时刷新配置（作为备用机制）
            scheduleConfigRefresh();
        } catch (Exception e) {
            log.error("初始化访问控制配置失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 加载访问控制配置
     */
    private void loadConfig() {
        try {
            ConfigService configService = nacosConfigManager.getConfigService();
            String configInfo = configService.getConfig(
                    accessControlProperties.getNacosDataId(),
                    group,
                    5000);
            
            if (configInfo != null && !configInfo.isEmpty()) {
                updateConfig(configInfo);
                log.info("成功加载访问控制配置");
            } else {
                log.warn("未找到访问控制配置，使用默认配置");
            }
        } catch (NacosException e) {
            log.error("加载访问控制配置失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 添加Nacos配置监听器
     */
    private void addConfigListener() {
        try {
            ConfigService configService = nacosConfigManager.getConfigService();
            configService.addListener(
                    accessControlProperties.getNacosDataId(),
                    group,
                    new Listener() {
                        @Override
                        public Executor getExecutor() {
                            return null;
                        }

                        @Override
                        public void receiveConfigInfo(String configInfo) {
                            log.info("接收到访问控制配置更新");
                            updateConfig(configInfo);
                        }
                    });
            log.info("已添加访问控制配置监听器");
        } catch (NacosException e) {
            log.error("添加访问控制配置监听器失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 定时刷新配置
     */
    private void scheduleConfigRefresh() {
        int interval = accessControlProperties.getRefreshInterval();
        if (interval <= 0) {
            interval = 30; // 默认30秒
        }
        
        scheduler.scheduleAtFixedRate(() -> {
            try {
                loadConfig();
            } catch (Exception e) {
                log.error("定时刷新访问控制配置失败: {}", e.getMessage(), e);
            }
        }, interval, interval, TimeUnit.SECONDS);
        
        log.info("已启动访问控制配置定时刷新任务，间隔: {}秒", interval);
    }

    /**
     * 更新配置
     */
    private void updateConfig(String configInfo) {
        try {
            AccessControlConfig config = objectMapper.readValue(configInfo, AccessControlConfig.class);
            
            // 更新IP白名单
            if (config.getIpWhitelist() != null) {
                accessControlProperties.getIpWhitelist().setEnabled(config.getIpWhitelist().isEnabled());
                accessControlProperties.getIpWhitelist().setIps(config.getIpWhitelist().getIps());
                accessControlProperties.getIpWhitelist().setIgnoreLocalhost(config.getIpWhitelist().isIgnoreLocalhost());
                accessControlProperties.getIpWhitelist().setBypassAuth(config.getIpWhitelist().isBypassAuth());
            }
            
            // 更新IP黑名单
            if (config.getIpBlacklist() != null) {
                accessControlProperties.getIpBlacklist().setEnabled(config.getIpBlacklist().isEnabled());
                accessControlProperties.getIpBlacklist().setIps(config.getIpBlacklist().getIps());
                accessControlProperties.getIpBlacklist().setMessage(config.getIpBlacklist().getMessage());
            }
            
            // 更新路径白名单
            if (config.getPathWhitelist() != null) {
                accessControlProperties.getPathWhitelist().setEnabled(config.getPathWhitelist().isEnabled());
                accessControlProperties.getPathWhitelist().setPaths(config.getPathWhitelist().getPaths());
                accessControlProperties.getPathWhitelist().setBypassAuth(config.getPathWhitelist().isBypassAuth());
                accessControlProperties.getPathWhitelist().setBypassRateLimit(config.getPathWhitelist().isBypassRateLimit());
            }
            
            // 更新路径黑名单
            if (config.getPathBlacklist() != null) {
                accessControlProperties.getPathBlacklist().setEnabled(config.getPathBlacklist().isEnabled());
                accessControlProperties.getPathBlacklist().setPaths(config.getPathBlacklist().getPaths());
                accessControlProperties.getPathBlacklist().setMessage(config.getPathBlacklist().getMessage());
            }
            
            // 更新安全配置
            if (config.getSecurityConfig() != null) {
                accessControlProperties.getSecurityConfig().setLogEnabled(config.getSecurityConfig().isLogEnabled());
                accessControlProperties.getSecurityConfig().setLogLevel(config.getSecurityConfig().getLogLevel());
                
                if (config.getSecurityConfig().getBlockResponse() != null) {
                    accessControlProperties.getSecurityConfig().getBlockResponse().setCode(
                            config.getSecurityConfig().getBlockResponse().getCode());
                    accessControlProperties.getSecurityConfig().getBlockResponse().setStatus(
                            config.getSecurityConfig().getBlockResponse().getStatus());
                    accessControlProperties.getSecurityConfig().getBlockResponse().setMessage(
                            config.getSecurityConfig().getBlockResponse().getMessage());
                    accessControlProperties.getSecurityConfig().getBlockResponse().setShowDetail(
                            config.getSecurityConfig().getBlockResponse().isShowDetail());
                }
            }
            
            log.info("访问控制配置已更新");
        } catch (Exception e) {
            log.error("解析访问控制配置失败: {}", e.getMessage(), e);
        }
    }
} 